﻿using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
using InterpriseSuiteEcommerceCommon.Extensions;
using System.Web;
using System.Text.RegularExpressions;

namespace InterpriseSuiteEcommerceCommon.Tool
{
    public class MenuManager
    {
        #region "Contructors"

        public MenuManager(string locale, string webSiteCode, bool cacheSetting = false, CachingOption cachingOptions = InterpriseSuiteEcommerceCommon.CachingOption.CacheOnHTTPContext) : this(AppLogic.DefaultSkinID(), locale, webSiteCode, cacheSetting, cachingOptions) { }

        public MenuManager(int skinId, string locale, string webSiteCode, bool cacheSetting = false, CachingOption cachingOptions = InterpriseSuiteEcommerceCommon.CachingOption.CacheOnHTTPContext) 
        {   
            SkinId = skinId;
            Locale = locale;
            CacheSetting = cacheSetting;
            CachingOption = cachingOptions;
            WebSiteCode = webSiteCode;
        }

        #endregion

        #region "Methods and Functions"

        public string GenerateMenu()
        {
            string html = string.Empty;
            if (CacheSetting)
            {
                string cachName = DomainConstants.TOP_MENU_CACHE_NAME + "_" + WebSiteCode;
                var cacheEngine = GetCacheEngine();
                if (cacheEngine.Exist(cachName))
                {
                    html = cacheEngine.GetItem<string>(cachName);
                }
                else
                { 
                    html = ProcessMenu();
                    int cacheMinutes = AppLogic.CacheDurationMinutes();
                    cacheEngine.AddItem(cachName, html, cacheMinutes);
                }
            }
            else
            {
                html = ProcessMenu();
            }
            return html;
        }

        private ICaching GetCacheEngine()
        {
            return (CachingOption == InterpriseSuiteEcommerceCommon.CachingOption.CacheOnHTTPContext) ?
                                        CachingFactory.RequestCachingEngineInstance: 
                                        CachingFactory.ApplicationCachingEngineInstance;
        }

        private string ProcessMenu() 
        {
            var xmlMenu = GenerateDynamicXmlDataFromLookUp();
            xmlMenu.Add(GenerateMiscelaneousEntries());

            var pakage = new XmlPackage2("rev.topmenu.xml.config", xmlMenu);
            return pakage.TransformString();
        }

        private XElement GenerateDynamicXmlDataFromLookUp()
        {
            string[] arrayLookUp = new string[] { DomainConstants.LOOKUP_HELPER_CATEGORIES, 
                                                  DomainConstants.LOOKUP_HELPER_DEPARTMENT,
                                                  DomainConstants.LOOKUP_HELPER_MANUFACTURERS };

            var root = new XElement(DomainConstants.XML_ROOT_NAME);
            foreach (string menulookup in arrayLookUp)
            {
                var entity = AppLogic.LookupHelper(menulookup);
                var entityDoc = entity.m_TblMgr.XmlDoc;
                if (entityDoc != null)
                {
                    var nav = entityDoc.CreateNavigator();
                    var iterator = nav.Select("root/Entity");
                    var rootEntity = new XElement(menulookup);
                    ExtractEntity(menulookup, nav.Select("root/Entity"), rootEntity);
                    root.Add(rootEntity);
                }
            }

            return root;
        }

        private XmlNode ExtractXmlNode(XPathNavigator nav)
        {
            return (nav as IHasXmlNode).GetNode();
        }

        //Recursive call to build the xml menu tree
        private void ExtractEntity(string entityName, XPathNodeIterator entityIterator, XElement rootEntity)
        {
            while (entityIterator.MoveNext())
            {
                var entityNode = ExtractXmlNode(entityIterator.Current);
                int entityId = entityNode.SelectSingleNode(@"EntityID").InnerText.Trim().TryParseInt().Value;
                string name = XmlCommon.XmlFieldByLocale(entityNode, "Description", Locale);
                string url = SE.MakeEntityLink(entityName, entityId.ToString(), name);

                var newItem = new XElement(DomainConstants.MENU_ITEM, XHelper.NewTextItem(name), XHelper.NewUrlItem(url));
                rootEntity.Add(newItem);
                ExtractEntity(entityName, entityNode.CreateNavigator().Select("Entity"), newItem);
            }
        }

        private XElement GenerateMiscelaneousEntries()
        {
            return new XElement("SKIN_SETUP", new XElement("SKIN_ID", SkinId));
        }

        private bool ShowStringResourceKey()
        {
            return AppLogic.AppConfigBool(DomainConstants.SHOWSTRING_RESOURCE_KEY);
        }

        public string TranslateStaticValuesByResource(string menupath)
        {
            Customer thisCustomer = Customer.Current;
            string menuXml = AppLogic.RunXmlPackage(menupath, null, thisCustomer, SkinId, string.Empty, null, false, false);

            Regex pattern = new Regex(@"\(!(.*?)!\)");
            MatchEvaluator findAndReplaceStringResourced = new MatchEvaluator(StringResourceMatch);
            return pattern.Replace(menuXml, findAndReplaceStringResourced);                
        }

        private string  StringResourceMatch(Match match)
        {
            string l = match.Groups[1].Value;
            string s = AppLogic.GetString(l, SkinId, Locale).ToHtmlEncode();
            if (s == null || s.Length == 0 || s == l)
            {
                s = match.Value;
            }
            return XmlCommon.XmlEncode(s);
        }

        public static void ResetCache()
        {
            RequestCachingEngine.Reset(DomainConstants.TOP_MENU_CACHE_NAME + "_" + InterpriseHelper.ConfigInstance.WebSiteCode);
            ApplicationCachingEngine.Reset(DomainConstants.TOP_MENU_CACHE_NAME + "_" + InterpriseHelper.ConfigInstance.WebSiteCode);
        }

        #endregion

        #region "Properties"

        public int SkinId { get; set; }

        public string Locale { get; set; }

        public bool CacheSetting { get; set; }

        public CachingOption CachingOption { get; set; }

        public string WebSiteCode { get; set; }

        #endregion
    }

    public class XHelper
    {
        public static XElement NewTextItem(string value)
        {
            return new XElement(DomainConstants.TEXT_NAME, value);
        }

        public static XElement NewUrlItem(string value)
        {
            return new XElement(DomainConstants.URL_NAME, value);
        }
    }
}